﻿/************************************************************************
 * CoreDES - A small and core library for discrete event systems
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     CoreDES\Execution\ReflectionHelper.cs
 * Description  :     Some reflection function helper
 * Change log   :     -17 sept 2011: major modifications
 *                    -2010: initial version (it originaly belongs to simgine library)
 * To Do        :
 ************************************************************************/

using System;
using System.Collections.Generic;
using System.Reflection;


namespace CoreDES.Execution
{
    /// <summary>
    /// System Reflection helper: some useful method which can be used during the execution by reflection
    /// </summary>
    public class ReflectionHelper
    {
        /// <summary>
        /// Flags used for accessing all members and typesOfEnums
        /// </summary>
        const BindingFlags modelBindingFlags =
            BindingFlags.Public |
            BindingFlags.NonPublic |
            BindingFlags.Static |
            BindingFlags.Instance;

        /// <summary>
        /// Check that a type "myType" implements an interface "myInterface" or not
        /// </summary>
        /// <param name="myType"></param>
        /// <param name="myInterface"></param>
        /// <returns></returns>
        public static bool ImplementsInterface(Type myType, Type myInterface)
        {
            //return myType.ImplementInterface(myInterface);
            foreach (Type t in myType.GetInterfaces())
                if (t == myInterface)
                    return true;
            return false;
        }

        /// <summary>
        /// Check whether a parameter is output or not
        /// </summary>
        /// <param name="pInfo"></param>
        /// <returns></returns>
        public static bool IsOutputParameter(ParameterInfo pInfo)
        {
            if (pInfo == null)
                throw new ArgumentNullException("pInfo");

            Type pType = (Type)pInfo.ParameterType;
            return (pInfo.IsOut || pType.IsByRef);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pInfo"></param>
        /// <returns></returns>
        public static bool IsInputParameter(ParameterInfo pInfo)
        {
            if (pInfo == null)
                throw new ArgumentNullException("pInfo");

            return !pInfo.IsOut;
        }

        /// <summary>
        /// Get fields with a partivular attribute
        /// </summary>
        /// <param name="myType">type</param>
        /// <param name="myAttrib">attriute</param>
        /// <returns>fields with the specified attributes</returns>
        public static IEnumerable<FieldInfo> GetFieldswithAttr(Type myType, Type myAttrib)
        {
            foreach (FieldInfo field in myType.GetFields(modelBindingFlags))
            {
                if (System.Attribute.GetCustomAttributes(field, myAttrib) != null)
                    yield return field;
            }
        }

        public static IEnumerable<FieldInfo> GetAttributesOf(MethodInfo m)
        {
            throw new NotImplementedException();
        }

        public static void GetAtrtributesOf(MethodInfo myMethod, Type myAttrib)
        {
            throw new NotImplementedException();
        }

        public static void GetAtrtributesOf(FieldInfo myMethod, Type myAttrib)
        {
            throw new NotImplementedException();
        }

        #region Method Related functions

        /// <summary>
        /// Get all implemented method in class
        /// </summary>
        /// <param name="myType"></param>
        /// <returns></returns>
        public static IEnumerable<MethodInfo> GetMethods(Type myType)
        {
            return myType.GetMethods();
        }

        /// <summary>
        /// Get all implemented methods in a class filtered by an attribute
        /// </summary>
        /// <param name="myType"></param>
        /// <param name="myAttrib"></param>
        /// <returns></returns>
        public static IEnumerable<MethodInfo> GetMethodswithAttr(Type myType, Type myAttrib)
        {
            foreach (MethodInfo m in myType.GetMethods())
            {
                if (System.Attribute.GetCustomAttributes(m, myAttrib) != null)
                    yield return m;
            }
        }


        public static object executeMethod(object obj, string methodName, object[] parameters)
        {
            return obj.GetType().GetMethod(methodName).Invoke(obj, parameters);
        }

        public static object executeStaticMethod(Type classType, string methodName, object[] parameters)
        {
            throw new Exception("Not implemented Yet!");
        }


        #endregion

        public static IEnumerable<FieldInfo> GetVariables(Type myType)
        {
            return myType.GetFields(modelBindingFlags);
        }

        public static IEnumerable<FieldInfo> GetVariableswithAttr(Type myType, Type myAttrib)
        {
            foreach (FieldInfo field in myType.GetMembers(modelBindingFlags))
            {
                if (System.Attribute.GetCustomAttributes(field, myAttrib) != null)
                    yield return field;
            }
        }


        public static object GetFieldValue(object obj, string memberName)
        {
            return obj.GetType().GetField(memberName).GetValue(obj);
        }

        public static void SetFieldValue(object obj, string memberName, object val)
        {
            obj.GetType().GetField(memberName).SetValue(obj, val);
        }

        public static object GetPropertyValue(object obj, string propertyName, object[] val)
        {
            throw new Exception("Not implemented Yet!");
        }

        public static void SetPropertyValue(object obj, string propertyName, object val)
        {
            throw new Exception("Not implemented Yet!");
        }

    }
}
